package net.ifilm.common;

import net.ifilm.db.DBExecutor;
import net.ifilm.domain.Film;
import net.ifilm.domain.Message;
import net.ifilm.util.PicCompress;
import net.ifilm.util.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;

class TaskRunnable extends Thread {

    private static final Log log = LogFactory.getLog(TaskRunnable.class);

    private boolean isRunning = false;

    private Queue<Message> messageQueue = null;

    private SpiderCache spiderCache = null;

    private DBExecutor dbExecutor = null;

    public TaskRunnable(Queue<Message> messageQueue, String threadName) {
        this.setName(threadName);
        this.messageQueue = messageQueue;
        spiderCache = SpiderCache.getInstance();
    }

    public void stopRunning() {
        isRunning = true;
    }

    @Override
    public void run() {
        Message message         = null;
        Document doc            = null;
        Film film               = null;
        int filmId              = 0;
        while (!isRunning) {
            message = messageQueue.get();
            dbExecutor = message.getDbExecutor();

            try {
                doc = getDocument(message.getFilmLinkPage());

                film = parseFilmObject(doc, message);   // 解析文档并入库电影对象
                if (!film.isExist()) {
                    relationFilmType(film);                 // 关联电影类型
                    relationFilmActor(film);                // 关联电影角色
                }

                relationFilmNetPath(film);              // 关联电影网络路径

                filmId = film.getFilmId();
                if (film.isExist()) { // 若电影已经存在只是增加了播放剧集则更新时间
                    dbExecutor.updateFileTime(new Date(), filmId);
                    if (log.isInfoEnabled()) {
                        log.info("update film id is " + filmId + " createtime");
                    }
                }

                if (log.isInfoEnabled()) {
                    log.info("the film id is " + filmId + " process complate");
                }
            } catch (Exception e) {
               log.error(e.toString());
            }
        }
    }

    private String generateMimageFileName(String imageFilmName, Message message) throws IOException {
        String storemFileName = PicCompress.cutImage(message.getDownloadPath(), imageFilmName);
        return storemFileName;
    }

    private String generateImageFileName(Document doc, Message message) throws IOException {
        String pictureUrl = StringUtil.adapterWord(null, doc.select(".moviecont dl dt img").attr("src"));
        File storeFile = picturePorcess(message.getDomain().concat(pictureUrl));
        if (storeFile != null) {
            String storeFileName = StringUtil.generateRandom() + "_a.jpg";
            PicCompress.compressPic(storeFile, message.getDownloadPath(),storeFileName,
                    Constants.DEFAULT_FILM_IMAGE_WIDTH,
                    Constants.DEFAULT_FILM_IMAGE_HEIGHT, false);
            storeFile.delete();
            return storeFileName;
        }
        return null;
    }

    private Film parseFilmObject(Document doc, Message message) throws IOException, SpiderException {
        Elements docElements    = doc.select(".moviecont dl dd.db");
        String filmName         = StringUtil.adapterWord(null, doc.select(".moviecont dl .bt h2").text());
        String resourceUrl      = doc.select(".playurl ul li").first().select("a").attr("href");

        Object value = SpiderCache.getInstance().getReverseFilmNameMapValue(filmName);
        Film film = new Film();
        if (value != null) {
            int filmId = (Integer)value;
            film.setResourceUrl(resourceUrl);
            film.setFilmId(filmId);
            film.setDomain(message.getDomain());
            film.setExist(true);

            return film;
        }

        filmName                = !"未知".equals(filmName) && filmName.length() > 20 ? filmName.substring(0, 20) : filmName;
        String filmTypeName     = StringUtil.adapterWord("类 型：", docElements.get(1).select("span.l").text());
        String filmActors       = StringUtil.adapterWord("主 演：", docElements.get(0).text());
        String regionName       = StringUtil.adapterWord("地 区：", docElements.get(1).select("span.r").text());
        String showTime         = StringUtil.adapterWord("上 映：", docElements.get(2).select("span.r").text());
        showTime                = !"未知".equals(showTime) && showTime.indexOf('年') != -1 ? showTime.replace("年", "") : showTime;
        String filmIntroduce    = StringUtil.adapterWord(null, doc.select(".descont ul").text());
        filmIntroduce           = !"未知".equals(filmIntroduce) && filmIntroduce.length() > 500 ? filmIntroduce.substring(0, 499) : filmIntroduce;
        int type                = StringUtil.getFilmType(filmTypeName);
        // filmStatus  = elements.get(2).select("span.l").text().replaceAll("状 态：", "");

        film.setFilmActors(filmActors);
        film.setResourceUrl(resourceUrl);
        film.setFilmTypeName(filmTypeName);
        film.setFilmIntroduce(filmIntroduce);
        film.setFilmName(filmName);
        film.setFilmTime("未知");
        film.setType(type);
        film.setShowTime(showTime);
        film.setRegionId(StringUtil.matchRegion(regionName));
        film.setClear(0);
        film.setLimit(1);
        film.setHot(0);
        film.setActiveFlag(0);
        film.setTags(filmName);
        film.setCreateTime(new Date());
        film.setDomain(message.getDomain());

        String imageFilmName = generateImageFileName(doc, message);
        film.setImagePath("/upload/film/spider/" + imageFilmName);
        String mImageFilmName = generateMimageFileName(imageFilmName, message);
        film.setmImagePath("/upload/film/spider/" + mImageFilmName);
        int filmId = dbExecutor.insertFilm(film);
        film.setFilmId(filmId);

        if (log.isDebugEnabled()) {
            log.debug("filmId is " + filmId + " addfilm success");
        }

        return film;
    }

    private void relationFilmType(Film film) throws SpiderException {
        int filmTypeId = StringUtil.matchFilmType(film.getFilmTypeName());
        dbExecutor.insertRelFilmType(film.getFilmId(), filmTypeId);

        if (log.isDebugEnabled()) {
            log.debug("filmId is " + film.getFilmId() + " add relation filmtype success");
        }
    }

    private void relationFilmActor(Film film) throws SpiderException {
        String[] actorList = StringUtil.matchFilmActors(film.getFilmActors());

        Object actorId = null;
        for (String actor : actorList) {
            actorId = spiderCache.getFilmActorMap().get(actor);
            if (actorId == null) {
                actorId = dbExecutor.insertStar(actor);
            }


            dbExecutor.insertRelStar(film.getFilmId(), (Integer)actorId);
        }

        if (log.isDebugEnabled()) {
            log.debug("filmId is " + film.getFilmId() + " add relation filmActor success");
        }
    }

    private void relationFilmNetPath(Film film) throws Exception {
        StringBuffer playUrl = new StringBuffer(film.getDomain());
        playUrl.append(film.getResourceUrl());

        Map<String, String> playUrlMap = parseFilmNetPath(playUrl.toString());
        if (playUrlMap.size() == 0) {
            throw new RuntimeException("filmId is " + film.getFilmId() + " playUrlMap size is 0");
        }

        /*
         * 若已经存在则更新后续剧集，不存在则更新全部剧集
         */
        if (film.isExist()) {
            Map<String, Object> filmPathMap = dbExecutor.findFilmPath(film.getFilmId());
            if (playUrlMap.size() > filmPathMap.size()) {
                dbExecutor.existBatchInsert(film.getFilmId(), filmPathMap, playUrlMap);

                if (log.isInfoEnabled()) {
                    log.info("update play url size " + (playUrlMap.size() - filmPathMap.size()));
                }
            }
        } else{
            dbExecutor.batchInsert(film.getFilmId(), playUrlMap);
        }

        if (log.isDebugEnabled()) {
            log.debug("filmId is " + film.getFilmId() + " relation filmNetPath success");
        }
    }

    private Map<String, String> parseFilmNetPath(String resourceUrl) throws Exception {
        Map<String, String> playUrlMap = new TreeMap<String, String>();

        String urlList = null;
        BufferedReader br = null;
        try {
            URL url = new URL(resourceUrl);
            InputStream inputStream = url.openStream();
            br = new BufferedReader(new InputStreamReader(inputStream));
            String line = br.readLine();
            while (line != null) {
                if (line.contains("url_list")) {
                    int startIndex = line.indexOf("url_list=");
                    urlList = line.substring(startIndex + 10, line.indexOf("\"", startIndex + 12));
                }
                line = br.readLine();
            }

            if (urlList == null || urlList.length() == 0) {
                throw new Exception("cann't find url_list keyword.");
            }

            String [] qvodUrls = urlList.split("%2B%2B%2B");
            if (qvodUrls == null || qvodUrls.length == 0) {
                throw new Exception("split qvodurl failure.");
            }

            for (String qvodUrl : qvodUrls) {
                qvodUrl = URLDecoder.decode(qvodUrl, "utf-8");
                Matcher m = StringUtil.extractPlayNetPath(qvodUrl);
                while (m.find()) {
                    playUrlMap.put(m.group(1), m.group(2));
                }
            }

            return playUrlMap;
        } finally {
            br.close();
        }
    }

    private Document getDocument(String filmWebPage) throws IOException {
        Connection conn = Jsoup.connect(filmWebPage);
        conn.timeout(Constants.CONNECT_TIMEOUT);
        Document doc = conn.get();
        return doc;
    }

    private File picturePorcess(String pictureUrl) throws IOException {
        long nanoTime = System.nanoTime();

        URL url = new URL(pictureUrl);
        InputStream inputStream = url.openStream();
        File file = new File(System.getProperty("java.io.tmpdir") + nanoTime + ".jpg");
        OutputStream outputStream = new FileOutputStream(file);
        int ch;
        while ((ch = inputStream.read()) != -1) {
            outputStream.write(ch);
        }

        return file;
    }

}
